﻿#define TEST_3

using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Profiling;

public delegate void OnTestDelegate();

public class DelegateTips : MonoBehaviour
{

    private OnTestDelegate m_onDelegate;

    private CustomDelegate m_customDelegate = new CustomDelegate();

    // Use this for initialization
    void Start()
    {

#if TEST_3

        //GC 104B
        m_onDelegate += OnTestDelegateCallback;
        //GC 104B
        m_onDelegate += OnTestDelegateCallback;
        //GC 104B
        m_onDelegate += OnTestDelegateCallback;
        //GC 104B
        m_onDelegate += OnTestDelegateCallback;

        //Total GC = 416B
#endif

#if TEST_4

        //GC 104B
        m_onDelegate = OnTestDelegateCallback;
#endif

    }

    // Update is called once per frame
    void Update()
    {
#if TEST_1
        Profiler.BeginSample("------ Test 1 ------");

        //GC 104B
        //原因是delegate的赋值（=）可以转化为： m_onDelegate = new OnTestDelegate (OnTestDelegateCallback);
        //所以这里会有GC
        m_onDelegate = OnTestDelegateCallback;

        Profiler.EndSample();
#endif

#if TEST_2
        Profiler.BeginSample("------ Test 2 ------");

        //GC 208B
        // += 等价于Delegate.Combine -= 等价于Delegate.Remove,都会有Clone的操作，所以2次 104B
        m_onDelegate += OnTestDelegateCallback;
        m_onDelegate -= OnTestDelegateCallback;

        Profiler.EndSample();
#endif

#if TEST_3
        Profiler.BeginSample("------ Test 3 ------");

        //GC 1.1KB
        //Delegate Combine 0.5KB; Delegate Remove 416B
        //这个测试，模拟delegate之前已经add了一些callback，然后在某些时候需要再add一个新的，这个时候GC是很大，
        // 由于在Start中+=了很多次，delegate变成multicast delegate，在调用Delegate.Combine这个方法时，
        // 会判断invocationlist的大小是否足够，所以会扩容这个list，所以这个list的越大，+=一次的代价就越大，gc越多
        m_onDelegate += OnTestDelegateCallback;
        m_onDelegate -= OnTestDelegateCallback;

        Profiler.EndSample();
#endif

#if TEST_4
        Profiler.BeginSample("------ Test 4-1 ------");

        //GC 208B
        //和TEST_1类似
        m_customDelegate.Add(OnTestDelegateCallback);
        m_customDelegate.Remove(OnTestDelegateCallback);

        Profiler.EndSample();

        Profiler.BeginSample("------ Test 4-2 ------");

        //GC 0
        //在Start时就已经赋值，所以保存的引用，并且也没有Delegate.Combine和Remove，所以没有GC
        m_customDelegate.Add(m_onDelegate);
        m_customDelegate.Remove(m_onDelegate);

        Profiler.EndSample();
#endif

    }

    private void OnTestDelegateCallback()
    {

    }
}

public class CustomDelegate
{
    private List<OnTestDelegate> m_listDelegate;

    public CustomDelegate()
    {
        m_listDelegate = new List<OnTestDelegate>(10);
    }

    public CustomDelegate(int capacity)
    {
        m_listDelegate = new List<OnTestDelegate>(capacity);
    }

    public void Add(OnTestDelegate del)
    {
        if (m_listDelegate.Contains(del) == false)
            m_listDelegate.Add(del);
    }

    public void Remove(OnTestDelegate del)
    {
        if (m_listDelegate.Contains(del) == true)
            m_listDelegate.Remove(del);
    }

    public void Invoke()
    {
        foreach(var del in m_listDelegate)
        {
            del.Invoke();
        }
    }
}
